package com.base.andlangcore.http

import com.apollographql.apollo3.api.ApolloResponse
import com.apollographql.apollo3.api.Operation
import kotlinx.coroutines.*
import java.net.SocketTimeoutException
import java.net.UnknownHostException
import java.util.concurrent.TimeoutException

/**
 * @Title: Peng
 * @Package com.simplez.ktcore.data
 * @Description: (用一句话描述该文件做什么)
 * @author MrSimpleZ
 * @date 2020/3/20 15:29
 * @version V1.0
 */

class Request<T> {

    private var request: (suspend () -> BaseResponse<T>)? = null

    private var response: ((BaseResponse<T>?) -> Unit)? = null

    internal var originResponse: ((BaseResponse<T>?) -> Unit)? = null

    private var start: (() -> Unit)? = null

    internal var success: ((T?) -> Unit)? = null

    internal var error: ((String) -> Unit)? = null

    internal var originError:((String)->Unit)?=null

    private var complete: (() -> Unit)? = null

    fun onStart(start: () -> Unit) {
        this.start = start
    }

    fun onRequest(request: suspend () -> BaseResponse<T>) {
        this.request = request
    }

    fun onSuccess(success: (T?) -> Unit) {
        this.success = success
    }

    fun onError(error: (String) -> Unit) {
        this.error = error
    }

    fun onRealError(error: (String) -> Unit) {
        this.originError = error
    }

    internal fun onResponse(response: (BaseResponse<T>?) -> Unit) {
        this.response = response
    }

    fun onRealResponse(response: (BaseResponse<T>?) -> Unit) {
        this.originResponse = response
    }

    fun onComplete(complete: () -> Unit) {
        this.complete = complete
    }

    internal fun toRequest(viewModelScope: CoroutineScope) {
        viewModelScope.launch(context = Dispatchers.Main) {
            start?.invoke()
            try {
                val realResponse = withContext(Dispatchers.IO) {
                    request?.invoke()
                }
                response?.invoke(realResponse)
            } catch (e: Exception) {
                when (e) {
                    is UnknownHostException -> error?.invoke(e.message!!)
                    is TimeoutException -> error?.invoke(e.message!!)
                    is SocketTimeoutException -> error?.invoke(e.message!!)
                    else -> error?.invoke(e.message!!)
                }
            } finally {
                complete?.invoke()
            }
        }
    }
}

class RequestApollo<T : Operation.Data> {

    private var request: (suspend () -> ApolloResponse<T>?)? = null

    private var response: ((ApolloResponse<T>?) -> Unit)? = null

    internal var originResponse: ((ApolloResponse<T>?) -> Unit)? = null

    private var start: (() -> Unit)? = null

    internal var success: ((T?) -> Unit)? = null

    internal var error: ((String) -> Unit)? = null

    internal var originError:((String)->Unit)?=null

    private var complete: (() -> Unit)? = null

    fun onStart(start: () -> Unit) {
        this.start = start
    }
    fun onRequest(request: (suspend () -> ApolloResponse<T>?)) {
        this.request = request
    }

    fun onSuccess(success: (T?) -> Unit) {
        this.success = success
    }

    fun onError(error: (String) -> Unit) {
        this.error = error
    }

    fun onRealError(error: (String) -> Unit) {
        this.originError = error
    }

    internal fun onResponse(response: (ApolloResponse<T>?) -> Unit) {
        this.response = response
    }

    fun onRealResponse(response: (ApolloResponse<T>?) -> Unit) {
        this.originResponse = response
    }

    fun onComplete(complete: () -> Unit) {
        this.complete = complete
    }

    internal fun toRequest(viewModelScope: CoroutineScope) {
        viewModelScope.launch(context = Dispatchers.Main) {
            start?.invoke()
            try {
                val realResponse = withContext(Dispatchers.IO) {
                    request?.invoke()
                }
                response?.invoke(realResponse)
            } catch (e: Exception) {
                when (e) {
                    is UnknownHostException -> error?.invoke(e.message!!)
                    is TimeoutException -> error?.invoke(e.message!!)
                    is SocketTimeoutException -> error?.invoke(e.message!!)
                    else -> error?.invoke(e.message!!)
                }
            } finally {
                complete?.invoke()
            }
        }
    }
}
